module riscv32_alu #(
	parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
	parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
	parameter [31:0] PROGADDR_RESET = 32'h 0000_0000,
	parameter [31:0] PROGADDR_IRQ = 32'h 0000_0004,
	parameter [31:0] STACKADDR = 32'h ffff_ffff
) (
	input clk, resetn,
	output reg trap,

	output reg        mem_valid,
	output reg        mem_instr,
	input             mem_ready,

	output reg [31:0] mem_addr,
	output reg [31:0] mem_wdata,
	output reg [ 3:0] mem_wstrb,
	input      [31:0] mem_rdata,

	// IRQ Interface
	input      [31:0] irq,
	output irq_state,

    // Pico Co-Processor Interface (PCPI)
	output reg        pcpi_valid,
	output     [31:0] pcpi_insn,
    output reg [31:0] pcpi_rs1,
    output reg [31:0] pcpi_rs2,
    input      [31:0] pcpi_rd,
    input             pcpi_reg_we,
	input             pcpi_error,
	input             pcpi_ready,
    output     [31:0] PC,
	// Trace Interface
    input             halt,
	output     [31:0] mret,
	output     [31:0] mcause,
    output     [31:0] mie
);

//reg [4:0] reg_raddr;
wire [4:0] reg_raddr;
reg [31:0] reg_rdata;
wire [4:0] reg_waddr;
reg [31:0] reg_wdata;

reg [31:0] user_x1;//user_ra
reg [31:0] user_x2;//user_sp
reg [31:0] irq_x1;//irq_ra
reg [31:0] irq_x2;//irq_sp
reg [31:0] x3;//gp
reg reg_we;
(* ram_style="block" *) reg [31:0] risc_v_reg [0:27];

wire [4:0] ram_reg_waddr;
assign ram_reg_waddr = reg_waddr - 5'd4;
wire [4:0] ram_reg_raddr;
assign ram_reg_raddr = reg_raddr - 5'd4;
// reg special_reg_we;
// reg [31:0] special_reg_wdata;
// reg reg [1:0] special_reg_waddr;
always @ (posedge clk) begin

    if((reg_we == 1'b1)&&(reg_waddr > 5'd3)) begin
        risc_v_reg[ram_reg_waddr] <= reg_wdata; 
    end
    
end
// 读寄存器1
always @ (*) begin
    if (reg_raddr == 5'd0) begin
        reg_rdata = 32'd0;
    // 如果读地址等于写地址，并且正在写操作，则直接返回写数据
    end else if ((reg_waddr == reg_raddr)&&(reg_we == 1'b1)) begin
        reg_rdata = reg_wdata;
    end else if(reg_raddr > 5'd3)begin
        reg_rdata = risc_v_reg[ram_reg_raddr];
    end
    else begin
        if(reg_raddr == 5'd1)begin
            if(irq_flag == 1'b1)begin
                reg_rdata <= irq_x1;
            end
            else begin
               reg_rdata <= user_x1;
            end
        end
        else if(reg_raddr == 5'd2)begin
            if(irq_flag == 1'b1)begin
               reg_rdata <= irq_x2;
            end
            else begin
               reg_rdata <= user_x2;
            end
        end
        else if(reg_raddr == 5'd3)begin
           reg_rdata <= x3;
        end
    end
end

reg [ 4:0] reg_raddr2;
reg [31:0] reg_rdata2;
wire [4:0] ram_reg_raddr2;
assign ram_reg_raddr2 = reg_raddr2 - 5'd4;
reg [4:0] reg_cnt;
always@(posedge clk) begin
    reg_cnt <= reg_cnt + 1'b1;
end
always@(posedge clk) begin
    if(reg_cnt == 5'h10) begin
        reg_raddr2 <= reg_raddr2 + 1'b1;
    end
    else begin
        reg_raddr2 <= reg_raddr2;
    end
end
// 读寄存器2
always @ (*) begin
    if (reg_raddr2 == 5'd0) begin
        reg_rdata2 = 32'd0;
    // 如果读地址等于写地址，并且正在写操作，则直接返回写数据
    end else if ((reg_waddr == reg_raddr2)&&(reg_we == 1'b1)) begin
        reg_rdata2 = reg_wdata;
    end else if(reg_raddr2 > 5'd3)begin
        reg_rdata2 = risc_v_reg[ram_reg_raddr2];
    end
    else begin
        if(reg_raddr2 == 5'd1)begin
            if(irq_flag == 1'b1)begin
                reg_rdata2 <= irq_x1;
            end
            else begin
               reg_rdata2 <= user_x1;
            end
        end
        else if(reg_raddr2 == 5'd2)begin
            if(irq_flag == 1'b1)begin
               reg_rdata2 <= irq_x2;
            end
            else begin
               reg_rdata2 <= user_x2;
            end
        end
        else if(reg_raddr2 == 5'd3)begin
           reg_rdata2 <= x3;
        end
    end
end
always trap = ^reg_rdata2;

//实现了检测irq上升沿功能
reg [31:0] irq_last;
always @(posedge clk) begin
    irq_last <= irq;
end
wire [31:0] irq_posedge;
assign irq_posedge = (~irq_last)&irq;

//下面是risc-v CPU逻辑
reg [31:0] risc_v_pc;

reg [31:0] irq_mask;
reg [31:0] mstatus;
reg [31:0] mret_reg;
reg [31:0] irq_reg;
reg [31:0] inst_latch;
reg [2:0] cpu_state;

reg [31:0] op1num;
reg [31:0] op2num;

wire[31:0] op1_add_op2_res;
wire op1_ge_op2_signed;
wire op1_ge_op2_unsigned;
wire op1_eq_op2;

//加法
assign op1_add_op2_res = op1num + op2num;
// 有符号数比较
assign op1_ge_op2_signed = $signed(op1num) >= $signed(op2num);
// 无符号数比较
assign op1_ge_op2_unsigned = (op1num >= op2num) ? 1'b1 : 1'b0;
assign op1_eq_op2 = (op1num == op2num) ? 1'b1 : 1'b0;

wire [31:0] num_shift_right_res;
assign num_shift_right_res = op1num >> op2num[4:0];

wire [31:0] num_shift_left_res;
assign num_shift_left_res = op1num << op2num[4:0];

wire [31:0] num1_sub_num2;
assign num1_sub_num2 = op1num - op2num;

wire [31:0] num_xor_res;
assign num_xor_res = op1num ^ op2num;

wire [31:0] num_or_res;
assign num_or_res = op1num | op2num;

wire [31:0] num_and_res;
assign num_and_res = op1num & op2num;

wire [31:0] num_sra_shift_right_res;
assign num_sra_shift_right_res = (num_shift_right_res | ({32{op1num[31]}} & (~(32'hffffffff >> op2num[4:0]))));

reg [31:0] mem_addr_add;
wire [31:0] mem_addr_add_res;
assign mem_addr_add_res = op1num + mem_addr_add;
wire [1:0] mem_raddr_index;
assign mem_raddr_index = mem_addr_add_res & 2'b11;

wire [1:0] mem_waddr_index;
assign mem_waddr_index = mem_addr_add_res & 2'b11;


parameter cpu_fetch0                  =   3'd0;
parameter cpu_fetch1                  =   3'd1;
parameter cpu_state_ld_rs1            =   3'd2;
parameter cpu_state_ld_rs2            =   3'd3;
parameter cpu_state_exec              =   3'd4;
parameter cpu_ex_ins_exec             =   3'd5;
parameter cpu_state_stmem             =   3'd6;
parameter cpu_state_ldmem             =   3'd7;
         
parameter LUI_INS                 =   7'b011_0111;
parameter AUIPC_INS               =   7'b001_0111;
parameter J_INS                   =   7'b110_1111;
parameter JALR_INS                =   7'b110_0111;
parameter B_TYPE_INS              =   7'b110_0011;
parameter I_TYPE_INS              =   7'b001_0011;
parameter L_TYPE_INS              =   7'b000_0011;
parameter S_TYPE_INS              =   7'b010_0011;
parameter R_TYPE_INS              =   7'b011_0011;
parameter MRS_TYPE_INS            =   7'b100_0011;
parameter MSR_TYPE_INS            =   7'b100_1011;
parameter IRQ_TYPE_INS            =   7'b100_1111;
parameter CSR_TYPE_INS            =   7'b111_0011;

reg [3:0] ins_cnt;
reg [31:0] temp_data;

wire [31:0] jump_res;
reg [31:0] jump_offset;
assign jump_res = risc_v_pc + jump_offset;

reg irq_flag;
wire irq_request;
assign irq_state = irq_flag;
assign mret = mret_reg;
assign mcause = irq_reg;
assign mie = irq_mask;
assign irq_request = ((irq_reg&irq_mask)!=32'h0) ? (~irq_flag): 1'b0;
reg [31:0] mtvec;



reg [31:0] i_type_imme;
always @(posedge clk) begin
    if(!resetn)begin
        i_type_imme <= 32'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        i_type_imme <= {{20{mem_rdata[31]}}, mem_rdata[31:20]};
    end
end

reg [31:0] b_type_imme;
always @(posedge clk) begin
    if(!resetn)begin
        b_type_imme <= 32'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        b_type_imme <= {{20{mem_rdata[31]}},mem_rdata[7],mem_rdata[30:25],mem_rdata[11:8],1'b0};
    end
end

reg [31:0] l_type_imme;
always @(posedge clk) begin
    if(!resetn)begin
        l_type_imme <= 32'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        l_type_imme <= {{20{mem_rdata[31]}}, mem_rdata[31:20]};
    end
end

reg [31:0] s_type_imme;
always @(posedge clk) begin
    if(!resetn)begin
        s_type_imme <= 32'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        s_type_imme <= {{20{mem_rdata[31]}}, mem_rdata[31:25], mem_rdata[11:7]};
    end
end
reg [31:0] u_type_imme;
always @(posedge clk) begin
    if(!resetn)begin
        u_type_imme <= 32'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        u_type_imme <= {mem_rdata[31:12],12'h0};
    end
end
reg [31:0] jal_type_imme;
always @(posedge clk) begin
    if(!resetn)begin
        jal_type_imme <= 32'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        jal_type_imme <= {{12{mem_rdata[31]}}, mem_rdata[19:12], mem_rdata[20], mem_rdata[30:21], 1'b0};
    end
end
reg [31:0] jalr_type_imme;
always @(posedge clk) begin
    if(!resetn)begin
        jalr_type_imme <= 32'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        jalr_type_imme <= {{20{mem_rdata[31]}}, mem_rdata[31:20]};
    end
end
reg [31:0] csr_type_imme;
always @(posedge clk) begin
    if(!resetn)begin
        csr_type_imme <= 32'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        csr_type_imme <= {{26{mem_rdata[19]}}, mem_rdata[19:15]};
    end
end
reg [4:0] rs1_addr;
always @(posedge clk) begin
    if(!resetn)begin
        rs1_addr <= 32'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        rs1_addr <= {mem_rdata[19:15]};
    end
end
reg [4:0] rs2_addr;
always @(posedge clk) begin
    if(!resetn)begin
        rs2_addr <= 32'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        rs2_addr <= {mem_rdata[24:20]};
    end
end
assign reg_raddr = (cpu_state == cpu_state_ld_rs1) ? rs1_addr : rs2_addr;//reg 操作数地址

reg [4:0] rd_addr;
always @(posedge clk) begin
    if(!resetn)begin
        rd_addr <= 5'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        rd_addr <= {mem_rdata[11:7]};
    end
end
assign reg_waddr = rd_addr;
reg [11:0] csr_addr;
always @(posedge clk) begin
    if(!resetn)begin
        csr_addr <= 12'h0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        csr_addr <= {mem_rdata[31:20]};
    end
end
wire lui_ins_flag;
assign lui_ins_flag    = (mem_rdata[6:0] == LUI_INS);
wire auipc_ins_flag;
assign auipc_ins_flag  = (mem_rdata[6:0] == AUIPC_INS);
wire j_type_ins_flag;
assign j_type_ins_flag = (mem_rdata[6:0] == J_INS);
wire jalr_ins_flag;
assign jalr_ins_flag   = (mem_rdata[6:0] == JALR_INS);
wire b_type_ins_flag;
assign b_type_ins_flag = (mem_rdata[6:0] == B_TYPE_INS);
wire i_type_ins_flag;
assign i_type_ins_flag = (mem_rdata[6:0] == I_TYPE_INS);
wire l_type_ins_flag;
assign l_type_ins_flag = (mem_rdata[6:0] == L_TYPE_INS);
wire s_type_ins_flag;
assign s_type_ins_flag = (mem_rdata[6:0] == S_TYPE_INS);
wire r_type_ins_flag;
assign r_type_ins_flag = (mem_rdata[6:0] == R_TYPE_INS);
wire csr_ins_flag;
assign csr_ins_flag    = (mem_rdata[6:0] == CSR_TYPE_INS );
reg lui_ins;
reg auipc_ins;
reg j_type_ins;
reg jalr_ins;
reg b_type_ins;
reg i_type_ins;
reg l_type_ins;
reg s_type_ins;
reg r_type_ins;
reg csr_ins;
always@(posedge clk )begin
    if(!resetn)begin
        lui_ins <= 1'b0;
        auipc_ins <= 1'b0;
        j_type_ins <= 1'b0;
        jalr_ins <= 1'b0;
        b_type_ins <= 1'b0;
        i_type_ins <= 1'b0;
        l_type_ins <= 1'b0;
        s_type_ins <= 1'b0;
        r_type_ins <= 1'b0;
        csr_ins <= 1'b0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        lui_ins    <= lui_ins_flag;
        auipc_ins  <= auipc_ins_flag;
        j_type_ins <= j_type_ins_flag;
        jalr_ins   <= jalr_ins_flag;
        b_type_ins <= b_type_ins_flag;
        i_type_ins <= i_type_ins_flag;
        l_type_ins <= l_type_ins_flag;
        s_type_ins <= s_type_ins_flag;
        r_type_ins <= r_type_ins_flag;
        csr_ins    <= csr_ins_flag;
    end
end
wire valid_ins_flag;
assign valid_ins_flag = lui_ins_flag | auipc_ins_flag | j_type_ins_flag | jalr_ins_flag | b_type_ins_flag | 
                    i_type_ins_flag | l_type_ins_flag | s_type_ins_flag | r_type_ins_flag | csr_ins_flag;
reg valid_ins1;//初步判断指令是否合法
always@(posedge clk) begin
    if(!resetn)begin
        valid_ins1 <= 1'b0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        valid_ins1 = (valid_ins_flag);
    end
end


//J指令
reg is_jalr_ins;
//B指令
reg is_beq_ins;
reg is_bne_ins;
reg is_blt_ins;
reg is_bge_ins;
reg is_bltu_ins;
reg is_bgeu_ins;
//L指令
reg is_lb_ins;
reg is_lh_ins;
reg is_lw_ins;
reg is_lbu_ins;
reg is_lhu_ins;
//S指令
reg is_sb_ins;
reg is_sh_ins;
reg is_sw_ins;
//I指令
reg is_addi_ins;
reg is_slti_ins;
reg is_sltiu_ins;
reg is_xori_ins;
reg is_ori_ins;
reg is_andi_ins;
reg is_slli_ins;
reg is_srli_ins;
reg is_srai_ins;
//R指令
reg is_add_ins;
reg is_sub_ins;
reg is_sll_ins;
reg is_slt_ins;
reg is_sltu_ins;
reg is_xor_ins;
reg is_srl_ins;
reg is_sra_ins;
reg is_or_ins;
reg is_and_ins;
//CSR指令
reg is_ecall_ebreak_mret;
reg is_csrrw_ins;
reg is_csrrs_ins;

always@(posedge clk )begin
    if(!resetn)begin
        is_jalr_ins  <= 1'b0;
        is_beq_ins   <= 1'b0;
        is_bne_ins   <= 1'b0;
        is_blt_ins   <= 1'b0;
        is_bge_ins   <= 1'b0;
        is_bltu_ins  <= 1'b0;
        is_bgeu_ins  <= 1'b0;
        is_lb_ins    <= 1'b0;
        is_lh_ins    <= 1'b0;
        is_lw_ins    <= 1'b0;
        is_lbu_ins   <= 1'b0;
        is_lhu_ins   <= 1'b0;
        is_sb_ins    <= 1'b0;
        is_sh_ins    <= 1'b0;
        is_sw_ins    <= 1'b0;
        is_addi_ins  <= 1'b0;
        is_slti_ins  <= 1'b0;
        is_sltiu_ins <= 1'b0;
        is_xori_ins  <= 1'b0;
        is_ori_ins   <= 1'b0;
        is_andi_ins  <= 1'b0;
        is_slli_ins  <= 1'b0;
        is_srli_ins  <= 1'b0;
        is_srai_ins  <= 1'b0;
        is_add_ins   <= 1'b0;
        is_sub_ins   <= 1'b0;
        is_sll_ins   <= 1'b0;
        is_slt_ins   <= 1'b0;
        is_sltu_ins  <= 1'b0;
        is_xor_ins   <= 1'b0;
        is_srl_ins   <= 1'b0;
        is_sra_ins   <= 1'b0;
        is_or_ins    <= 1'b0;
        is_and_ins   <= 1'b0;
        is_ecall_ebreak_mret <= 1'b0;
        is_csrrw_ins <= 1'b0;
        is_csrrs_ins <= 1'b0;
    end
    else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        is_jalr_ins  <= jalr_ins_flag & (mem_rdata[14:12] == 3'b000);
        is_beq_ins   <= b_type_ins_flag & (mem_rdata[14:12] == 3'b000);
        is_bne_ins   <= b_type_ins_flag & (mem_rdata[14:12] == 3'b001);
        is_blt_ins   <= b_type_ins_flag & (mem_rdata[14:12] == 3'b100);
        is_bge_ins   <= b_type_ins_flag & (mem_rdata[14:12] == 3'b101);
        is_bltu_ins  <= b_type_ins_flag & (mem_rdata[14:12] == 3'b110);
        is_bgeu_ins  <= b_type_ins_flag & (mem_rdata[14:12] == 3'b111);
        is_lb_ins    <= l_type_ins_flag & (mem_rdata[14:12] == 3'b000);
        is_lh_ins    <= l_type_ins_flag & (mem_rdata[14:12] == 3'b001);
        is_lw_ins    <= l_type_ins_flag & (mem_rdata[14:12] == 3'b010);
        is_lbu_ins   <= l_type_ins_flag & (mem_rdata[14:12] == 3'b100);
        is_lhu_ins   <= l_type_ins_flag & (mem_rdata[14:12] == 3'b101);
        is_sb_ins    <= s_type_ins_flag & (mem_rdata[14:12] == 3'b000);
        is_sh_ins    <= s_type_ins_flag & (mem_rdata[14:12] == 3'b001);
        is_sw_ins    <= s_type_ins_flag & (mem_rdata[14:12] == 3'b010);
        is_addi_ins  <= i_type_ins_flag & (mem_rdata[14:12] == 3'b000);
        is_slti_ins  <= i_type_ins_flag & (mem_rdata[14:12] == 3'b010);
        is_sltiu_ins <= i_type_ins_flag & (mem_rdata[14:12] == 3'b011);
        is_xori_ins  <= i_type_ins_flag & (mem_rdata[14:12] == 3'b100);
        is_ori_ins   <= i_type_ins_flag & (mem_rdata[14:12] == 3'b110);
        is_andi_ins  <= i_type_ins_flag & (mem_rdata[14:12] == 3'b111);
        is_slli_ins  <= i_type_ins_flag & (mem_rdata[14:12] == 3'b001);
        is_srli_ins  <= i_type_ins_flag & (mem_rdata[14:12] == 3'b101) & (mem_rdata[31:25] == 7'b0000000);
        is_srai_ins  <= i_type_ins_flag & (mem_rdata[14:12] == 3'b101) & (mem_rdata[31:25] == 7'b0100000);
        is_add_ins   <= r_type_ins_flag & (mem_rdata[14:12] == 3'b000) & (mem_rdata[31:25] == 7'b0000000);
        is_sub_ins   <= r_type_ins_flag & (mem_rdata[14:12] == 3'b000) & (mem_rdata[31:25] == 7'b0100000);
        is_sll_ins   <= r_type_ins_flag & (mem_rdata[14:12] == 3'b001);
        is_slt_ins   <= r_type_ins_flag & (mem_rdata[14:12] == 3'b010);
        is_sltu_ins  <= r_type_ins_flag & (mem_rdata[14:12] == 3'b011);
        is_xor_ins   <= r_type_ins_flag & (mem_rdata[14:12] == 3'b100);
        is_srl_ins   <= r_type_ins_flag & (mem_rdata[14:12] == 3'b101) & (mem_rdata[31:25] == 7'b0000000);
        is_sra_ins   <= r_type_ins_flag & (mem_rdata[14:12] == 3'b101) & (mem_rdata[31:25] == 7'b0100000);
        is_or_ins    <= r_type_ins_flag & (mem_rdata[14:12] == 3'b110);
        is_and_ins   <= r_type_ins_flag & (mem_rdata[14:12] == 3'b111);
        is_ecall_ebreak_mret <= csr_ins_flag & (mem_rdata[14:12] == 3'b000);
        is_csrrw_ins <= csr_ins_flag & (mem_rdata[14:12] == 3'b001);
        is_csrrs_ins <= csr_ins_flag & (mem_rdata[14:12] == 3'b010);
    end
end

reg [31:0] risc_v_next_pc;
always@(posedge clk )begin
    if(!resetn)begin
        risc_v_next_pc <= 32'd0;
    end
     else if((mem_instr == 1'b1) && (mem_ready == 1'b1))begin
        risc_v_next_pc <= risc_v_pc + 4'd4;
    end
end
reg ins_ready_1_clk;//取指令完成标志延时一个时钟周期
always@(posedge clk) begin
    ins_ready_1_clk <= mem_ready&mem_instr;
end

reg valid_ins2;//细节判断指令是否合法
always@(posedge clk) begin
    if(!resetn)begin
        valid_ins2 <= 1'b0;
    end
    else begin
        valid_ins2 <= is_jalr_ins | is_beq_ins | is_bne_ins | is_blt_ins | is_bge_ins | is_bltu_ins | is_bgeu_ins //JALR指令和B指令
        | is_lb_ins | is_lh_ins | is_lw_ins | is_lbu_ins | is_lhu_ins | is_sb_ins | is_sh_ins  |is_sw_ins //L指令和S指令
        | is_addi_ins |is_slti_ins | is_sltiu_ins | is_xori_ins | is_ori_ins | is_andi_ins | is_slli_ins | is_srli_ins | is_srai_ins //I指令
        | is_add_ins | is_sub_ins | is_sll_ins | is_slt_ins | is_sltu_ins | is_xor_ins | is_srl_ins | is_sra_ins | is_or_ins | is_and_ins //R指令
        | is_ecall_ebreak_mret | is_csrrw_ins | is_csrrs_ins//CSR指令
        | lui_ins | auipc_ins | j_type_ins;
    end
end
assign pcpi_insn = inst_latch;
always@(posedge clk )begin
    if(!resetn)begin
        risc_v_pc <= PROGADDR_RESET;
        irq_mask <= 32'h0;
        cpu_state <= cpu_fetch0;
        irq_flag <= 1'b0;
        irq_reg <= 32'h0;
        reg_we <= 1'b0;
        ins_cnt <= 4'd0;
        pcpi_valid <= 1'b0;
        mem_valid <= 1'b0;
        mtvec <= PROGADDR_IRQ;
    end
    else begin
        reg_we <= 1'b0;
        ins_cnt <= 4'd0;


        irq_reg <= irq_reg | irq_posedge;
        case(cpu_state)
            cpu_fetch0:begin
                mem_valid <= 1'b1;
                mem_wstrb <= 4'b0000;
                jump_offset <= 32'h0;
                mem_instr <= 1'b1;
                pcpi_valid <= 1'b0;
                ins_cnt   <= 4'd0;
                reg_we <= 1'b0;//无论怎么此处必须将reg_we 置 0
                
                if(irq_request == 1'b1)begin
                    mret_reg <= risc_v_pc;//异步中断
                    risc_v_pc <= mtvec;
                    mem_addr <= mtvec;
                    irq_flag <= 1'b1;    
                end
                else begin
                    mem_addr <= risc_v_pc;
                end
                if(halt == 1'b1) begin
                    cpu_state <= cpu_fetch0;
                end
                else begin
                    cpu_state <= cpu_fetch1;
                end
            end
            cpu_fetch1:begin
                risc_v_pc <= risc_v_pc;
                if(mem_ready)begin
                    mem_valid <= 1'b0;
                    mem_instr <= 1'b0;
                    inst_latch <= mem_rdata;
                    cpu_state <= cpu_state_ld_rs1;
                end
                else begin
                    cpu_state <= cpu_state;
                    mem_valid <= mem_valid;
                    mem_instr <= mem_instr;
                    ins_cnt   <= 4'd0;
                end
            end
            cpu_state_ld_rs1:begin
                mem_valid = 1'b0;
                risc_v_pc <= risc_v_pc;
                cpu_state <= cpu_state_ld_rs1;
            (* parallel_case *)
                case (1'b1)
                    lui_ins || auipc_ins || j_type_ins :begin
                        op1num <=  lui_ins ? 0 : risc_v_pc;
                        op2num <= u_type_imme;
                        jump_offset <= jal_type_imme;
                        cpu_state <= cpu_state_exec;
                    end
                    j_type_ins :begin
                        
                    end
                    b_type_ins :begin
                        jump_offset <= b_type_imme;//B指令可能跳转地址
                    end
                    b_type_ins || r_type_ins || s_type_ins : begin
                        cpu_state <= cpu_state_ld_rs2;
                    end
                    (valid_ins2 == 1'b0):begin
                        cpu_state <= cpu_state_ld_rs2;
                    end
                    jalr_ins :begin
                        op1num <= reg_rdata;//jalr 操作数1；
                        op2num <= jalr_type_imme;//跳转地址从加法操作结果得出
                        cpu_state <= cpu_state_exec;
                    end
                    b_type_ins || r_type_ins:begin
                        op1num <= reg_rdata;
                    end
                    s_type_ins :begin
                        op1num <= reg_rdata;
                        mem_addr_add <= s_type_imme;
                    end
                    l_type_ins :begin
                        op1num <= reg_rdata;
                        mem_addr_add <= l_type_imme;
                        cpu_state <= cpu_state_ldmem;//等到进入cpu_state_ldmem状态时在请求接收数据因为需要延时一个clk
                    end
                    i_type_ins:begin
                        op1num <= reg_rdata;
                        op2num <= i_type_imme;
                        cpu_state <= cpu_state_exec;
                    end
                    csr_ins:begin
                        op1num <= reg_rdata;
                        cpu_state <= cpu_state_exec;
                    end
                endcase
            end
            cpu_state_ld_rs2:begin
                mem_valid = 1'b0;
                risc_v_pc <= risc_v_pc;
                op2num <= reg_rdata;//操作数2
                cpu_state <= cpu_state_exec;
                
                (* parallel_case *)
                case (1'b1)
                    (valid_ins2 == 1'b0):begin
                        pcpi_rs1 <= op1num;
                        pcpi_rs2 <= reg_rdata;
                        pcpi_valid <= 1'b1;
                        cpu_state <= cpu_ex_ins_exec;
                    end
                    s_type_ins:begin
                        mem_valid <= 1'b0;
                        mem_addr  <= mem_addr_add_res;
                        (* parallel_case *)
                        case(1'b1)
                            is_sb_ins:begin
                                mem_wdata = {4{reg_rdata[7:0]}};
                                case (mem_waddr_index)
                                    2'b00: begin
                                        mem_wstrb <= 4'b0001;
                                    end
                                    2'b01: begin
                                        mem_wstrb <= 4'b0010;
                                    end
                                    2'b10: begin
                                        mem_wstrb <= 4'b0100;
                                    end
                                    default: begin
                                        mem_wstrb <= 4'b1000;
                                    end
                                endcase
                            end
                            is_sh_ins:begin
                                mem_wdata = {2{reg_rdata[15:0]}};
                                if (mem_waddr_index == 2'b00) begin
                                    mem_wstrb <= 4'b0011;
                                end else begin
                                    mem_wstrb <= 4'b1100;
                                end
                            end
                            is_sw_ins:begin
                                mem_wstrb <= 4'b1111;
                                mem_wdata = reg_rdata;
                            end
                        endcase
                        cpu_state <= cpu_state_stmem;//存数据指令
                    end
                endcase
            end
            cpu_state_exec:begin
                mem_valid = 1'b0;
                reg_we    <= 1'b1;
                risc_v_pc <= risc_v_next_pc;
                cpu_state <= cpu_fetch0;                                
                (* parallel_case *)
                case(1'b1)
                    is_add_ins || is_addi_ins || lui_ins || auipc_ins :begin
                        reg_wdata <= op1_add_op2_res;
                    end
                    is_sub_ins:begin
                    reg_wdata <= num1_sub_num2;
                    end
                    is_sll_ins || is_slli_ins:begin
                        reg_wdata <= num_shift_left_res;
                    end
                    is_sra_ins || is_srai_ins:begin
                        reg_wdata <= num_sra_shift_right_res;
                    end
                    is_srl_ins || is_srli_ins:begin
                        reg_wdata <= num_shift_right_res;
                    end
                    is_slt_ins || is_slti_ins:begin
                        if(op1_ge_op2_signed==1'b0) begin
                            reg_wdata <= 32'h00000001;
                        end
                        else begin
                            reg_wdata <= 32'h00000000;
                        end
                    end
                    is_sltu_ins || is_sltiu_ins :begin
                        if(op1_ge_op2_unsigned==1'b0) begin
                            reg_wdata <= 32'h00000001;
                        end
                        else begin
                            reg_wdata <= 32'h00000000;
                        end
                    end
                    is_xor_ins || is_xori_ins :begin
                        reg_wdata <= num_xor_res;
                    end
                    is_or_ins || is_ori_ins :begin
                        reg_wdata <= num_or_res;
                    end
                    is_and_ins || is_andi_ins :begin
                        reg_wdata <= num_and_res;
                    end
                    is_beq_ins:begin
                        reg_we    <= 1'b0;
                        if(op1_eq_op2==1'b1)begin
                            risc_v_pc <= jump_res;
                        end
                    end
                    is_bne_ins:begin
                        reg_we    <= 1'b0;
                        if(op1_eq_op2 != 1'b1)begin
                            risc_v_pc <= jump_res;                            
                        end
                    end
                    is_blt_ins:begin
                        reg_we    <= 1'b0;
                        if(op1_ge_op2_signed == 1'b0)begin
                            risc_v_pc <= jump_res;
                        end
                    end
                    is_bge_ins:begin
                        reg_we    <= 1'b0;
                        if(op1_ge_op2_signed==1'b1)begin
                            risc_v_pc <= jump_res;
                        end
                    end
                    is_bltu_ins:begin
                        reg_we    <= 1'b0;
                        if(op1_ge_op2_unsigned == 1'b0)begin
                            risc_v_pc <= jump_res;
                        end
                    end
                    is_bgeu_ins:begin
                        reg_we    <= 1'b0;
                        if(op1_ge_op2_unsigned==1'b1)begin
                            risc_v_pc <= jump_res;
                        end
                    end
                    j_type_ins :begin
                        risc_v_pc <= jump_res;
                        reg_wdata <= risc_v_next_pc;
                    end
                    jalr_ins :begin
                        risc_v_pc <= op1_add_op2_res;
                        reg_wdata <= risc_v_next_pc;
                    end
                    
                    is_ecall_ebreak_mret :begin
                        reg_we    <= 1'b0;
                        case(csr_addr)
                            12'h302:begin//mret
                                irq_flag <= 1'b0;
                                irq_reg <= irq_reg;
                                risc_v_pc <= mret_reg;
                            end
                            12'h000:begin//ecall
                                irq_reg <= irq_reg | 32'h80000000;
                                mret_reg <= risc_v_pc + 32'h4;//同步中断
                                risc_v_pc <= mtvec; 
                                irq_flag <= 1'b1;//直接进中断
                            end
                            12'h001:begin//ebreak
                                irq_reg <= irq_reg | 32'h40000000;
                                mret_reg <= risc_v_pc + 32'h4;//同步中断
                                risc_v_pc <= mtvec;
                                irq_flag <= 1'b1;//直接进中断
                            end
                        endcase
                    end
                    is_csrrw_ins :begin
                        if(rs1_addr!=12'h0) begin
                            case(csr_addr)
                                12'h341:begin//mret_reg --> mepc
                                    mret_reg <= op1num;
                                end
                                12'h342:begin//irq_reg --> mcause
                                    irq_reg <= op1num;
                                end
                                12'h304:begin//irq_mask --> mie
                                    irq_mask <= op1num;
                                end
                                12'h305:begin
                                    mtvec <= op1num;
                                end
                                12'h300:begin//mstatus
                                    mstatus <= op1num;
                                end
                                12'hff0:begin//reg [31:0] user_x1;//user_ra
                                    user_x1 <= op1num;
                                end
                                12'hff1:begin//reg [31:0] user_x2;//user_sp
                                    user_x2 <= op1num;
                                end
                                12'hff2:begin//reg [31:0] irq_x1;//irq_ra
                                    irq_x1 <= op1num;
                                end
                                12'hff2:begin//reg [31:0] irq_x2;//irq_sp
                                    irq_x2 <= op1num;
                                end
                            endcase
                        end
                        if(rd_addr == 12'h0) begin
                            reg_we <= 1'b0;
                        end
                        else begin
                            reg_we <= 1'b1;
                            case(csr_addr)
                                12'h341:begin//mret_reg --> mepc
                                    reg_wdata <= mret_reg;
                                end
                                12'h342:begin//irq_reg --> mcause
                                    reg_wdata <= irq_reg;
                                end
                                12'h304:begin//irq_mask --> mie
                                    reg_wdata <= irq_mask;
                                end
                                12'h305:begin
                                    reg_wdata <= mtvec;
                                end
                                12'h300:begin//mstatus
                                    reg_wdata <= mstatus;
                                end
                                12'hff0:begin//reg [31:0] user_x1;//user_ra
                                    reg_wdata <= user_x1;
                                end
                                12'hff1:begin//reg [31:0] user_x2;//user_sp
                                    reg_wdata <= user_x2;
                                end
                                12'hff2:begin//reg [31:0] irq_x1;//irq_ra
                                    reg_wdata <= irq_x1;
                                end
                                12'hff2:begin//reg [31:0] irq_x2;//irq_sp
                                    reg_wdata <= irq_x2;
                                end
                            endcase
                        end
                    end                    
                    is_csrrs_ins :begin
                        if(rs1_addr!=12'h0)begin
                            case(csr_addr)
                                12'h341:begin//mret_reg --> mepc
                                    mret_reg <= op1num|mret_reg;
                                end
                                12'h342:begin//irq_reg --> mcause
                                    irq_reg <= op1num|irq_reg;
                                end
                                12'h304:begin//irq_mask --> mie
                                    irq_mask <= op1num|irq_mask;
                                end
                                12'h305:begin
                                    mtvec <= op1num|mtvec;
                                end
                                12'h300:begin//mstatus
                                    mstatus <= op1num|mstatus;
                                end
                                12'hff0:begin//reg [31:0] user_x1;//user_ra
                                    user_x1 <= op1num|user_x1;
                                end
                                12'hff1:begin//reg [31:0] user_x2;//user_sp
                                    user_x2 <= op1num|user_x2;
                                end
                                12'hff2:begin//reg [31:0] irq_x1;//irq_ra
                                        irq_x1 <= op1num|irq_x1;
                                    end
                                12'hff2:begin//reg [31:0] irq_x2;//irq_sp
                                    irq_x2 <= op1num|irq_x2;
                                end
                            endcase
                        end
                        if(rd_addr == 12'h0) begin
                            reg_we    <= 1'b0;
                        end
                        else begin
                            reg_we <= 1'b1;
                            case(csr_addr)
                                12'h341:begin//mret_reg --> mepc
                                    reg_wdata <= mret_reg;
                                end
                                12'h342:begin//irq_reg --> mcause
                                    reg_wdata <= irq_reg;
                                end
                                12'h304:begin//irq_mask --> mie
                                    reg_wdata <= irq_mask;
                                end
                                12'h305:begin
                                    reg_wdata <= mtvec;
                                end
                                12'h300:begin//mstatus
                                    reg_wdata <= mstatus;
                                end
                                12'hff0:begin//reg [31:0] user_x1;//user_ra
                                    reg_wdata <= user_x1;
                                end
                                12'hff1:begin//reg [31:0] user_x2;//user_sp
                                    reg_wdata <= user_x2;
                                end
                                12'hff2:begin//reg [31:0] irq_x1;//irq_ra
                                    reg_wdata <= irq_x1;
                                end
                                12'hff2:begin//reg [31:0] irq_x2;//irq_sp
                                    reg_wdata <= irq_x2;
                                end
                            endcase
                        end
                    end 
                endcase
            end
            cpu_ex_ins_exec:begin
                mem_valid = 1'b0;
                cpu_state <= cpu_ex_ins_exec;
                pcpi_valid <= 1'b1;
                risc_v_pc <= risc_v_pc;
                if(((pcpi_error == 1'b1)||(pcpi_ready == 1'b1))&&(pcpi_valid == 1'b1))begin
                    cpu_state <= cpu_fetch0;
                    pcpi_valid <= 1'b0;
                    if(pcpi_error)begin
                        reg_we <= 1'b0;
                        irq_reg <= irq_reg | 32'h20000000;
                        mret_reg <= risc_v_next_pc;
                        risc_v_pc <= mtvec;
                        irq_flag <= 1'b1;
                    end
                    else begin
                        risc_v_pc <= risc_v_next_pc;
                        reg_wdata <= pcpi_rd;
                        reg_we    <=  pcpi_reg_we;
                    end
                end
            end
            cpu_state_stmem:begin
                mem_valid <= 1'b1;
                if(mem_ready) begin
                    mem_valid <= 1'b0;
                    mem_wstrb <= 4'b0000;//置为0
                    cpu_state <= cpu_fetch0;
                    risc_v_pc <= risc_v_next_pc;
                end
            end
            cpu_state_ldmem:begin
                mem_valid <= 1'b1;//置1请求数据
                mem_addr  <= mem_addr_add_res;//传输地址
                if(mem_ready) begin
                    mem_valid <= 0;
                    risc_v_pc <= risc_v_next_pc;
                    cpu_state <= cpu_fetch0;
                    reg_we    <= 1'b1;
                    (* parallel_case*)
                    case(1'b1)
                        is_lb_ins:begin
                            case(mem_raddr_index)
                                2'b00: begin
                                    reg_wdata <= {{24{mem_rdata[7]}}, mem_rdata[7:0]};
                                end
                                2'b01: begin
                                    reg_wdata <= {{24{mem_rdata[15]}}, mem_rdata[15:8]};
                                end
                                2'b10: begin
                                    reg_wdata <= {{24{mem_rdata[23]}}, mem_rdata[23:16]};
                                end
                                default: begin
                                    reg_wdata <= {{24{mem_rdata[31]}}, mem_rdata[31:24]};
                                end
                            endcase
                        end
                        is_lh_ins:begin
                            if (mem_raddr_index == 2'b0) begin
                                reg_wdata <= {{16{mem_rdata[15]}}, mem_rdata[15:0]};
                            end
                            else begin
                                reg_wdata <= {{16{mem_rdata[31]}}, mem_rdata[31:16]};
                            end
                        end
                        is_lw_ins:begin
                            reg_wdata <= mem_rdata;
                        end
                        is_lbu_ins:begin
                            case(mem_raddr_index)
                                2'b00: begin
                                    reg_wdata <= {24'h0, mem_rdata[7:0]};
                                end
                                2'b01: begin
                                    reg_wdata <= {24'h0, mem_rdata[15:8]};
                                end
                                2'b10: begin
                                    reg_wdata <= {24'h0, mem_rdata[23:16]};
                                end
                                default: begin
                                    reg_wdata <= {24'h0, mem_rdata[31:24]};
                                end
                            endcase
                        end
                        is_lhu_ins:begin
                            if (mem_raddr_index == 2'b0) begin
                                reg_wdata <= {16'h0, mem_rdata[15:0]};
                            end
                            else begin
                                reg_wdata <= {16'h0, mem_rdata[31:16]};
                            end
                        end
                    endcase
                end
            end
        endcase
    end
    //Special function register 特殊功能寄存器-->方便操作系统
    if(reg_we == 1'b1) begin
        if(reg_waddr == 5'd1)begin
            if(irq_flag == 1'b1)begin
                irq_x1 <= reg_wdata;
            end
            else begin
                user_x1 <= reg_wdata;
            end
        end
        else if(reg_waddr == 5'd2)begin
            if(irq_flag == 1'b1)begin
                irq_x2 <= reg_wdata;
            end
            else begin
                user_x2 <= reg_wdata;
            end
        end
        else if(reg_waddr == 5'd3)begin
            x3 <= reg_wdata;
        end
    end
end
assign PC = risc_v_pc;
endmodule
